Skip to content

BUG: Index.copy() honors 'name' parameter (#14302) #14303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

BUG: Index.copy() honors 'name' parameter (#14302) #14303

wants to merge 1 commit into from

Conversation

chrisaycock
Copy link
Contributor

@@ -629,7 +629,7 @@ def copy(self, name=None, deep=False, dtype=None, **kwargs):
name = name or deepcopy(self.name)
else:
new_index = self._shallow_copy()
name = self.name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although admittedly nicer to use or, this will stop people using 0 or an empty string as a name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. The "deep copy" path above uses or too. Are empty strings permitted as Index names?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are empty strings permitted as Index names?

Technically, yes. It's safer and more idiomatic to use if name is None.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roger. Will fix.

@codecov-io
Copy link

codecov-io commented Sep 26, 2016

Current coverage is 85.26% (diff: 88.46%)

Merging #14303 into master will decrease coverage by <.01%

@@             master     #14303   diff @@
==========================================
  Files           140        140          
  Lines         50598      50608    +10   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits          43141      43149     +8   
- Misses         7457       7459     +2   
  Partials          0          0          

Powered by Codecov. Last update 977b384...bbfc79f

levels = self.levels
labels = self.labels
names = self.names
levels = levels if levels is not None else self.levels
Copy link
Member

@shoyer shoyer Sep 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it's an extra line, but less code to read/write:

if levels is None:
    levels = self.levels

@chrisaycock
Copy link
Contributor Author

@shoyer @MaximilianR Any further comments?

Copy link
Member

@shoyer shoyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jreback jreback added Bug Indexing Related to indexing on series/frames, not to indexes themselves labels Sep 26, 2016
idx = pd.Index([1, 2], name='MyName')
idx2 = idx.copy(name='NewName')

self.assertTrue(idx.equals(idx2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should accept name or names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Turns out I was overwriting names!

multi_idx = pd.Index([(1, 2), (3, 4)], names=['MyName1', 'MyName2'])
multi_idx2 = multi_idx.copy(names=['NewName1', 'NewName2'])

self.assertTrue(multi_idx.equals(multi_idx2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MultiIndex.copy() does not have a scalar name parameter, only the array names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, these signature should be the same (for Index and MI). This whole name/names biz is unfortunate, but need to maintain it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add name to MultiIndex as part of this patch then? What would the semantics mean then? We can't just duplicate the user's input n times since that would be a naming conflict.

Copy link
Contributor

@jreback jreback Sep 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do things like this (from memory), so have a look how we do that elsewhere (you can pull out to a function if you want)

if names is not None and name is not None:
    raise ValueError(....)
if names is None:
    names = name

if names is not None and name is not None:
raise TypeError("Can only provide one of `names` and `name`")
if names is None:
names = name
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I assume that the user has passed-in a list for name. A scalar entry for a MultiIndex doesn't make any sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most/all of this can be pulled out of Base.copy and made into a private function, maybe _validate_name(name=name, names=names) (which you can then use in both .copy

        names = kwargs.get('names')
        if names is not None and name is not None:
            raise TypeError("Can only provide one of `names` and `name`")
        if deep:
            from copy import deepcopy
            new_index = self._shallow_copy(self._data.copy())
            name = name or deepcopy(self.name)
        else:
            new_index = self._shallow_copy()
            name = self.name
        if name is not None:
            names = [name]

if names is not None and name is not None:
raise TypeError("Can only provide one of `names` and `name`")
if names is None:
names = name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most/all of this can be pulled out of Base.copy and made into a private function, maybe _validate_name(name=name, names=names) (which you can then use in both .copy

        names = kwargs.get('names')
        if names is not None and name is not None:
            raise TypeError("Can only provide one of `names` and `name`")
        if deep:
            from copy import deepcopy
            new_index = self._shallow_copy(self._data.copy())
            name = name or deepcopy(self.name)
        else:
            new_index = self._shallow_copy()
            name = self.name
        if name is not None:
            names = [name]

@chrisaycock
Copy link
Contributor Author

@jreback I refactored the validation of name/names, but then Travis failed with

ERROR: File or directory already exists: /Users/travis/miniconda

I'm not sure what to make of this.

@jreback
Copy link
Contributor

jreback commented Sep 27, 2016

@chrisaycock I restarted the failed osx job. ping when all green. lgtm.

@jreback jreback added this to the 0.19.0 milestone Sep 27, 2016
@jreback jreback closed this in df50e88 Sep 27, 2016
@jreback
Copy link
Contributor

jreback commented Sep 27, 2016

thanks @chrisaycock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Indexing Related to indexing on series/frames, not to indexes themselves
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Index.copy() ignores name/names arguments
5 participants